package com.xiaozhu.utils;

import com.xiaozhu.common.aiconstant.LockConstants;
import com.xiaozhu.enumreation.LockState;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.function.Supplier;

/**
 * @author 朱慧军
 * @version 1.0
 *
 * 分布式锁模板类（推荐做法）
 * 用于统一管理加锁、重试、释放逻辑，支持函数式回调。
 *
 */
@Slf4j
@Component
public class RedisLockTemplate {

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 执行带分布式锁保护的操作
     *
     * @param key        锁的 key（例如 lock:chat:123）
     * @param requestId  唯一标识（推荐 UUID 或用户ID）
     * @param action     加锁成功后要执行的操作（函数式接口）
     * @param <T>        返回值类型
     * @return           执行结果
     */
    public <T> T executeWithLock(String key, String requestId, Supplier<T> action){
        // 初始化锁的状态
        LockState state = LockState.UNLOCKED;
        int retryCount = 0;

        // 尝试加锁
        try {
            state = LockState.LOCKING;
            while (! (redisUtils.tryLock(key, requestId, LockConstants.LOCK_EXPIRE_MS))){
                retryCount ++;
                if (retryCount > LockConstants.MAX_RETRY){
                    state = LockState.TIMEOUT;
                    log.warn("加锁超时了：{}", key);
                    throw new RuntimeException("获取锁失败了");
                }
                // 先休眠100ms,释放cpu ,防止堵塞了
                Thread.sleep(LockConstants.RETRY_INTERVAL_MS);
            }

            state = LockState.LOCKED;
            log.info("加锁成功");
            // 执行逻辑
            return action.get();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            if(state == LockState.LOCKED){
                // 释放锁，防止堵塞
                redisUtils.unlock(key, requestId);
            }
        }


    }

}
